using System;
using System.Runtime.InteropServices;
using System.Text;
using HANDLE = System.IntPtr;
using HWND = System.IntPtr;
using HDC = System.IntPtr;

namespace Win32
{
    /// <summary>
    /// Audio Mixer
    /// http://msdn.microsoft.com/en-us/library/dd756701(v=VS.85).aspx
    /// 
    /// Audio Mixer Reference
    /// http://msdn.microsoft.com/en-us/library/dd756706%28v=VS.85%29.aspx
    /// </summary>
    public class XP
    {
        public class Api
        {
            /// <summary>
            /// get Mixer count
            /// </summary>
            /// <returns></returns>
            [DllImport("winmm")]
            public static extern int mixerGetNumDevs();

            /// <summary>
            /// get Mixer info
            /// </summary>
            /// <param name="uMxId"></param>
            /// <param name="pmxcaps"></param>
            /// <param name="cbmxcaps"></param>
            /// <returns></returns>
            [DllImport("winmm")]
            public static extern int mixerGetDevCaps(int uMxId, ref Structs.MIXERCAPS pmxcaps, int cbmxcaps);

            /// <summary>
            /// get Mixer Handle
            /// </summary>
            /// <param name="phmx"></param>
            /// <param name="uMxId"></param>
            /// <param name="dwCallback"></param>
            /// <param name="dwInstance"></param>
            /// <param name="fdwOpen"></param>
            /// <returns></returns>
            [DllImport("winmm")]
            public static extern int mixerOpen(out IntPtr phmx, int uMxId, IntPtr dwCallback, IntPtr dwInstance, XP.Enums.mixerOpenFlags fdwOpen);

            /// <summary>
            /// close Mixer Handle 
            /// </summary>
            /// <param name="hmx"></param>
            /// <returns></returns>
            [DllImport("winmm")]
            public static extern int mixerClose(HANDLE hmx);

            /// <summary>
            /// get info of specific MIXERLINE
            /// </summary>
            /// <param name="hmxobj"></param>
            /// <param name="pmxl"></param>
            /// <param name="fdwInfo"></param>
            /// <returns></returns>
            [DllImport("winmm")]
            public static extern int mixerGetLineInfo(HANDLE hmxobj, ref Structs.MIXERLINE pmxl, Enums.lineInfoFlags fdwInfo);

            /// <summary>
            /// get MIXERLINECONTROLS from specific MIXERLINE
            /// </summary>
            /// <param name="hmxobj"></param>
            /// <param name="pmxlc"></param>
            /// <param name="fdwControls"></param>
            /// <returns></returns>
            [DllImport("winmm")]
            public static extern int mixerGetLineControls(HANDLE hmxobj, ref Structs.MIXERLINECONTROLS pmxlc, Enums.lineControlsFlags fdwControls);

            /// <summary>
            /// get MIXERCONTROLDETAILS from specific MIXERCONTROL
            /// </summary>
            /// <param name="hmxobj"></param>
            /// <param name="pmxcd"></param>
            /// <param name="fdwDetails"></param>
            /// <returns></returns>
            [DllImport("winmm")]
            public static extern int mixerGetControlDetails(HANDLE hmxobj, ref Structs.MIXERCONTROLDETAILS pmxcd, XP.Enums.ControlDetailsFlags fdwDetails);

            /// <summary>
            /// set MIXERCONTROLDETAILS from specific MIXERCONTROL
            /// </summary>
            /// <param name="hmxobj"></param>
            /// <param name="pmxcd"></param>
            /// <param name="fdwDetails"></param>
            /// <returns></returns>
            [DllImport("winmm")]
            public static extern int mixerSetControlDetails(HANDLE hmxobj, ref Structs.MIXERCONTROLDETAILS pmxcd, XP.Enums.ControlDetailsFlags fdwDetails);
        }
        public class Structs
        {
            /// <summary>
            /// information of a mixer
            /// </summary>
            public struct MIXERCAPS
            {
                // A manufacturer identifier 
                public short wMid;

                // A product identifier
                public short wPid;

                // Version number of the mixer device driver.
                public int vDriverVersion;

                // Name of the product.
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
                public string szPname;

                // Various support information for the mixer device driver.
                public int fdwSupport;

                // The number of audio line destinations available through the mixer device. 
                public int cDestinations;
            }
            
            /// <summary>
            /// mixer line info
            /// </summary>
            public struct MIXERLINE
            {
                // Size, in bytes, of the MIXERLINE structure. 
                public int cbStruct;

                // Destination line index. [MIXERCAPS.cDestinations[?]]
                public int dwDestination;

                // Index for the audio source line associated with the dwDestination member [MIXERLINE.cConnections[?]]
                public int dwSource;

                // An identifier defined by the mixer device that uniquely refers to the audio line described by the MIXERLINE structure
                public int dwLineID;

                // An identifier defined by the mixer device that uniquely refers to the audio line described by the MIXERLINE structure. 
                public int fdwLine;

                // Instance data defined by the audio device for the line.
                public int dwUser;

                // Component type for this audio line.
                public Enums.COMPONENTTYPE dwComponentType;

                // Maximum number of separate channels that can be manipulated independently for the audio line.
                public int cChannels;
                
                // Number of connections that are associated with the audio line.
                public int cConnections;

                // Number of controls associated with the audio line. 
                public int cControls;

                // Short string that describes the audio mixer line specified in the dwLineID member.
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
                public string szShortName;

                // String that describes the audio mixer line specified in the dwLineID member.
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
                public string szName;

                // Target media information.
                public TARGET tTarget;
            }    
            /// <summary>
            /// mixer line target [similer MIXERCAPS struct]
            /// </summary>
            public struct TARGET
            {
                public int dwType;
                public int dwDeviceID;
                public short wMid;
                public short wPid;
                public int vDriverVersion;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
                public string szPname;
            }

            /// <summary>
            /// controls of a mixer
            /// </summary>
            [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode, Pack = 1)]
            public struct MIXERLINECONTROLS
            {
                // Size, in bytes, of the MIXERLINECONTROLS structure. 
                [FieldOffset(0)]
                public UInt32 cbStruct;

                // Line identifier for which controls are being queried. 
                [FieldOffset(4)]
                public UInt32 dwLineID;

                // Union start
                [FieldOffset(8)]
                public UInt32 dwControlID;

                // Control identifier of the desired control.
                [FieldOffset(8)]
                public XP.Enums.CONTROLTYPE dwControlType;

                // Number of MIXERCONTROL structure elements to retrieve. 
                [FieldOffset(12)]
                public UInt32 cControls;

                // Size, in bytes, of a single MIXERCONTROL structure.
                [FieldOffset(16)]
                public UInt32 cbmxctrl;

                // Pointer to one or more MIXERCONTROL structures to receive the properties of the requested audio line controls.
                [FieldOffset(20)]
                public IntPtr pamxctrl;
            }
            /// <summary>
            /// control from MIXERLINECONTROLS
            /// </summary>
            public struct MIXERCONTROL
            {
                // Size, in bytes, of the MIXERCONTROL structure.
                public int cbStruct;

                // Audio mixer-defined identifier that uniquely refers to the control described by the MIXERCONTROL structure. 
                public int dwControlID;

                // Class of the control for which the identifier is specified in dwControlID.
                public XP.Enums.CONTROLTYPE dwControlType;

                // Status and support flags for the audio line control.
                public XP.Enums.CONTROLF fdwControl;

                // Number of items per channel that make up a MIXERCONTROL_CONTROLF_MULTIPLE control.
                public int cMultipleItems;

                // Short string that describes the audio line control specified by dwControlID.
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
                public string szShortName;

                // String that describes the audio line control specified by dwControlID.
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
                public string szName;

                // Union of boundary types.
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
                public int[] Bounds;

                // Union of boundary metrics.
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
                public int[] Metrics;
            }

            /// <summary>
            /// details [volume / mute]
            /// </summary>
            public struct MIXERCONTROLDETAILS
            {
                // Size, in bytes, of the MIXERCONTROLDETAILS structure. 
                public int cbStruct;

                // Control identifier on which to get or set properties.
                public int dwControlID;

                // Number of channels on which to get or set control properties.
                // if control is a MIXERCONTROL_CONTROLTYPE_CUSTOM control      --> 0
                // ELSE if control is a MIXERCONTROL_CONTROLF_UNIFORM control   --> 1
                // ELSE                                                         --> MIXERLINE.cChannels
                public int cChannels;

                // hmm ... WTF ?
                public int item;

                // Size, in bytes { Mute :: 1-0, Volume :: 0-65535 }
                public int cbDetails;

                // (Size of int) * cChannels}
                // Pointer to an array of one or more structures
                // in which properties for the specified control are retrieved or set.
                public IntPtr paDetails;
            }
        }
        public class Enums
        {
            //
            // FOR API
            //

            /// <summary>
            /// MixerOpen               -> information to query
            /// </summary>
            [Flags]
            public enum mixerOpenFlags : uint
            {
                /// <summary>
                /// The dwCallback parameter is assumed to be a window handle (HWND).
                /// </summary>
                CALLBACK_WINDOW = 0x00010000,

                /// <summary>
                /// WTF ? what it do ?!
                /// </summary>
                MIXER_OBJECTF_HANDLE = 0x80000000,

                /// <summary>
                /// The hmxobj parameter is a mixer device identifier in the range of zero to one less than the number of devices returned by the mixerGetNumDevs function.
                /// This flag is optional.
                /// </summary>
                MIXER_OBJECTF_MIXER = 0x00000000,

                /// <summary>
                /// The hmxobj parameter is a mixer device handle returned by the mixerOpen function.
                /// This flag is optional.
                /// </summary>
                MIXER_OBJECTF_HMIXER = MIXER_OBJECTF_HANDLE | MIXER_OBJECTF_MIXER,

                /// <summary>
                /// The hmxobj parameter is the identifier of a waveform-audio output device in the range of zero to one less
                /// than the number of devices returned by the waveOutGetNumDevs function.
                /// </summary>
                MIXER_OBJECTF_WAVEOUT = 0x10000000,

                /// <summary>
                /// The hmxobj parameter is a waveform-audio output handle returned by the waveOutOpen function.
                /// </summary>
                MIXER_OBJECTF_HWAVEOUT = MIXER_OBJECTF_HANDLE | MIXER_OBJECTF_WAVEOUT,

                /// <summary>
                /// The hmxobj parameter is the identifier of a waveform-audio input device in the range of zero to one less
                /// than the number of devices returned by the waveInGetNumDevs function.
                /// </summary>
                MIXER_OBJECTF_WAVEIN = 0x20000000,

                /// <summary>
                /// The hmxobj parameter is a waveform-audio input handle returned by the waveInOpen function.
                /// </summary>
                MIXER_OBJECTF_HWAVEIN = MIXER_OBJECTF_HANDLE | MIXER_OBJECTF_WAVEIN,

                /// <summary>
                /// he hmxobj parameter is the identifier of a MIDI output device.
                /// This identifier must be in the range of zero to one less than the number of devices returned by the midiOutGetNumDevs function.
                /// </summary>
                MIXER_OBJECTF_MIDIOUT = 0x30000000,

                /// <summary>
                /// he hmxobj parameter is the handle of a MIDI output device. This handle must have been returned by the midiOutOpen function.
                /// </summary>
                MIXER_OBJECTF_HMIDIOUT = MIXER_OBJECTF_HANDLE | MIXER_OBJECTF_MIDIOUT,

                /// <summary>
                /// The hmxobj parameter is the identifier of a MIDI input device.
                /// This identifier must be in the range of zero to one less than the number of devices returned by the midiInGetNumDevs function.
                /// </summary>
                MIXER_OBJECTF_MIDIIN = 0x40000000,

                /// <summary>
                /// The hmxobj parameter is the handle of a MIDI input device.
                /// This handle must have been returned by the midiInOpen function.
                /// </summary>
                MIXER_OBJECTF_HMIDIIN = MIXER_OBJECTF_HANDLE | MIXER_OBJECTF_MIDIIN,

                /// <summary>
                /// The hmxobj parameter is an auxiliary device identifier in the range of zero to one less than the number of devices returned by the auxGetNumDevs function.
                /// </summary>
                MIXER_OBJECTF_AUX = 0x50000000
            }

            /// <summary>
            /// getMixerLine            -> information to query
            /// </summary>
            [Flags]
            public enum lineInfoFlags : uint
            {
                /// <summary>
                /// The pmxl parameter will receive information about the first audio line of the type specified in the dwComponentType member of the MIXERLINE structure.
                /// his flag is used to retrieve information about an audio line of a specific component type. Remaining structure members except cbStruct require no further initialization.
                /// </summary>
                MIXER_GETLINEINFOF_COMPONENTTYPE = 0x3,

                /// <summary>
                /// The pmxl parameter will receive information about the destination audio line specified by the dwDestination member of the MIXERLINE structure.
                /// his index ranges from zero to one less than the value in the cDestinations member of the MIXERCAPS structure.
                /// All remaining structure members except cbStruct require no further initialization.
                /// </summary>
                MIXER_GETLINEINFOF_DESTINATION = 0x0,

                /// <summary>
                /// The pmxl parameter will receive information about the audio line specified by the dwLineID member of the MIXERLINE structure.
                /// This is usually used to retrieve updated information about the state of an audio line. All remaining structure members except cbStruct require no further initialization.
                /// </summary>
                MIXER_GETLINEINFOF_LINEID = 0x2,

                /// <summary>
                /// The pmxl parameter will receive information about the source audio line specified by the dwDestination and dwSource members of the MIXERLINE structure.
                /// The index specified by dwDestination ranges from zero to one less than the value in the cDestinations member of the MIXERCAPS structure.
                /// The index specified by dwSource ranges from zero to one less than the value in the cConnections member of the MIXERLINE structure returned
                /// for the audio line stored in the dwDestination member. 
                /// All remaining structure members except cbStruct require no further initialization.
                /// </summary>
                MIXER_GETLINEINFOF_SOURCE = 0x1,

                /// <summary>
                /// The pmxl parameter will receive information about the audio line that is for the dwType member of the Target structure, which is a member of the MIXERLINE structure. 
                /// This flag is used to retrieve information about an audio line that handles the target type (for example, MIXERLINE_TARGETTYPE_WAVEOUT).
                /// The application must initialize the dwType, wMid, wPid, vDriverVersion and szPname members of the MIXERLINE structure before calling mixerGetLineInfo.
                /// All of these values can be retrieved from the device capabilities structures for all media devices.
                /// Remaining structure members except cbStruct require no further initialization.
                /// </summary>
                MIXER_GETLINEINFOF_TARGETTYPE = 0x4,

                /// <summary>
                /// WTF ? what it do ?!
                /// </summary>
                MIXER_GETLINEINFOF_QUERYMASK = 0xF,

                /// <summary>
                /// WTF ? what it do ?!
                /// </summary>
                MIXER_OBJECTF_HANDLE = 0x80000000,

                /// <summary>
                /// The hmxobj parameter is a mixer device identifier in the range of zero to one less than the number of devices returned by the mixerGetNumDevs function.
                /// This flag is optional.
                /// </summary>
                MIXER_OBJECTF_MIXER = 0x00000000,

                /// <summary>
                /// The hmxobj parameter is a mixer device handle returned by the mixerOpen function.
                /// This flag is optional.
                /// </summary>
                MIXER_OBJECTF_HMIXER = MIXER_OBJECTF_HANDLE | MIXER_OBJECTF_MIXER,

                /// <summary>
                /// The hmxobj parameter is the identifier of a waveform-audio output device in the range of zero to one less
                /// than the number of devices returned by the waveOutGetNumDevs function.
                /// </summary>
                MIXER_OBJECTF_WAVEOUT = 0x10000000,

                /// <summary>
                /// The hmxobj parameter is a waveform-audio output handle returned by the waveOutOpen function.
                /// </summary>
                MIXER_OBJECTF_HWAVEOUT = MIXER_OBJECTF_HANDLE | MIXER_OBJECTF_WAVEOUT,

                /// <summary>
                /// The hmxobj parameter is the identifier of a waveform-audio input device in the range of zero to one less
                /// than the number of devices returned by the waveInGetNumDevs function.
                /// </summary>
                MIXER_OBJECTF_WAVEIN = 0x20000000,

                /// <summary>
                /// The hmxobj parameter is a waveform-audio input handle returned by the waveInOpen function.
                /// </summary>
                MIXER_OBJECTF_HWAVEIN = MIXER_OBJECTF_HANDLE | MIXER_OBJECTF_WAVEIN,

                /// <summary>
                /// he hmxobj parameter is the identifier of a MIDI output device.
                /// This identifier must be in the range of zero to one less than the number of devices returned by the midiOutGetNumDevs function.
                /// </summary>
                MIXER_OBJECTF_MIDIOUT = 0x30000000,

                /// <summary>
                /// he hmxobj parameter is the handle of a MIDI output device. This handle must have been returned by the midiOutOpen function.
                /// </summary>
                MIXER_OBJECTF_HMIDIOUT = MIXER_OBJECTF_HANDLE | MIXER_OBJECTF_MIDIOUT,

                /// <summary>
                /// The hmxobj parameter is the identifier of a MIDI input device.
                /// This identifier must be in the range of zero to one less than the number of devices returned by the midiInGetNumDevs function.
                /// </summary>
                MIXER_OBJECTF_MIDIIN = 0x40000000,

                /// <summary>
                /// The hmxobj parameter is the handle of a MIDI input device.
                /// This handle must have been returned by the midiInOpen function.
                /// </summary>
                MIXER_OBJECTF_HMIDIIN = MIXER_OBJECTF_HANDLE | MIXER_OBJECTF_MIDIIN,

                /// <summary>
                /// The hmxobj parameter is an auxiliary device identifier in the range of zero to one less than the number of devices returned by the auxGetNumDevs function.
                /// </summary>
                MIXER_OBJECTF_AUX = 0x50000000,
            }

            /// <summary>
            /// GetLineControls         -> information to query
            /// </summary>
            [Flags]
            public enum lineControlsFlags : uint
            {
                /// <summary>
                /// The pmxlc parameter references a list of MIXERCONTROL structures that will receive information on all controls associated with the audio line identified
                /// by the dwLineID member of the MIXERLINECONTROLS structure.
                /// </summary>
                MIXER_GETLINECONTROLSF_ALL = 0x0,

                /// <summary>
                /// The pmxlc parameter references a single MIXERCONTROL structure that will receive information on the control identified
                /// by the dwControlID member of the MIXERLINECONTROLS structure.
                /// </summary>
                MIXER_GETLINECONTROLSF_ONEBYID = 0x1,

                /// <summary>
                /// The mixerGetLineControls function retrieves information about the first control of a specific class for the audio line that is being queried
                /// </summary>
                MIXER_GETLINECONTROLSF_ONEBYTYPE = 0x2,

                /// <summary>
                /// nothing in MSDN
                /// </summary>
                MIXER_GETLINECONTROLSF_QUERYMASK = 0xF,

                MIXER_OBJECTF_HANDLE = 0x80000000,
                MIXER_OBJECTF_MIXER = 0x00000000,
                MIXER_OBJECTF_HMIXER = MIXER_OBJECTF_HANDLE | MIXER_OBJECTF_MIXER,
                MIXER_OBJECTF_WAVEOUT = 0x10000000,
                MIXER_OBJECTF_HWAVEOUT = MIXER_OBJECTF_HANDLE | MIXER_OBJECTF_WAVEOUT,
                MIXER_OBJECTF_WAVEIN = 0x20000000,
                MIXER_OBJECTF_HWAVEIN = MIXER_OBJECTF_HANDLE | MIXER_OBJECTF_WAVEIN,
                MIXER_OBJECTF_MIDIOUT = 0x30000000,
                MIXER_OBJECTF_HMIDIOUT = MIXER_OBJECTF_HANDLE | MIXER_OBJECTF_MIDIOUT,
                MIXER_OBJECTF_MIDIIN = 0x40000000,
                MIXER_OBJECTF_HMIDIIN = MIXER_OBJECTF_HANDLE | MIXER_OBJECTF_MIDIIN,
                MIXER_OBJECTF_AUX = 0x50000000,
            }

            /// <summary>
            /// [Get/Set]ControlDetails -> information to query
            /// </summary>
            [Flags]
            public enum ControlDetailsFlags : uint
            {
                /// <summary>
                /// WTF ? what it do ?!
                /// </summary>
                MIXER_OBJECTF_HANDLE = 0x80000000,

                /// <summary>
                /// The hmxobj parameter is a mixer device identifier in the range of zero to one less than the number of devices returned by the mixerGetNumDevs function.
                /// This flag is optional.
                /// </summary>
                MIXER_OBJECTF_MIXER = 0x00000000,

                /// <summary>
                /// The hmxobj parameter is a mixer device handle returned by the mixerOpen function.
                /// This flag is optional.
                /// </summary>
                MIXER_OBJECTF_HMIXER = MIXER_OBJECTF_HANDLE | MIXER_OBJECTF_MIXER,

                /// <summary>
                /// The hmxobj parameter is the identifier of a waveform-audio output device in the range of zero to one less
                /// than the number of devices returned by the waveOutGetNumDevs function.
                /// </summary>
                MIXER_OBJECTF_WAVEOUT = 0x10000000,

                /// <summary>
                /// The hmxobj parameter is a waveform-audio output handle returned by the waveOutOpen function.
                /// </summary>
                MIXER_OBJECTF_HWAVEOUT = MIXER_OBJECTF_HANDLE | MIXER_OBJECTF_WAVEOUT,

                /// <summary>
                /// The hmxobj parameter is the identifier of a waveform-audio input device in the range of zero to one less
                /// than the number of devices returned by the waveInGetNumDevs function.
                /// </summary>
                MIXER_OBJECTF_WAVEIN = 0x20000000,

                /// <summary>
                /// The hmxobj parameter is a waveform-audio input handle returned by the waveInOpen function.
                /// </summary>
                MIXER_OBJECTF_HWAVEIN = MIXER_OBJECTF_HANDLE | MIXER_OBJECTF_WAVEIN,

                /// <summary>
                /// he hmxobj parameter is the identifier of a MIDI output device.
                /// This identifier must be in the range of zero to one less than the number of devices returned by the midiOutGetNumDevs function.
                /// </summary>
                MIXER_OBJECTF_MIDIOUT = 0x30000000,

                /// <summary>
                /// he hmxobj parameter is the handle of a MIDI output device. This handle must have been returned by the midiOutOpen function.
                /// </summary>
                MIXER_OBJECTF_HMIDIOUT = MIXER_OBJECTF_HANDLE | MIXER_OBJECTF_MIDIOUT,

                /// <summary>
                /// The hmxobj parameter is the identifier of a MIDI input device.
                /// This identifier must be in the range of zero to one less than the number of devices returned by the midiInGetNumDevs function.
                /// </summary>
                MIXER_OBJECTF_MIDIIN = 0x40000000,

                /// <summary>
                /// The hmxobj parameter is the handle of a MIDI input device.
                /// This handle must have been returned by the midiInOpen function.
                /// </summary>
                MIXER_OBJECTF_HMIDIIN = MIXER_OBJECTF_HANDLE | MIXER_OBJECTF_MIDIIN,

                /// <summary>
                /// The hmxobj parameter is an auxiliary device identifier in the range of zero to one less than the number of devices returned by the auxGetNumDevs function.
                /// </summary>
                MIXER_OBJECTF_AUX = 0x50000000,

                /// <summary>
                /// The current value(s) for a control are get.
                /// The paDetails member of the MIXERCONTROLDETAILS structure points to one or more mixer-control details structures of the appropriate class for the control.
                /// </summary>
                MIXER_GETCONTROLDETAILSF_VALUE = 0x0,

                /// <summary>
                /// The current value(s) for a control are set.
                /// The paDetails member of the MIXERCONTROLDETAILS structure points to one or more mixer-control details structures of the appropriate class for the control.
                /// </summary>
                MIXER_SETCONTROLDETAILSF_VALUE = 0x0
            }

            //
            // FOR STRUCT
            //

            /// <summary>
            /// mixerline -> dwComponentType
            /// Component type for this audio line.
            /// </summary>
            [Flags]
            public enum COMPONENTTYPE : uint
            {
                // HMMMMMM.
                MIXERLINE_COMPONENTTYPE_DST_FIRST = 0x0,
                MIXERLINE_COMPONENTTYPE_DST_LAST = (MIXERLINE_COMPONENTTYPE_DST_FIRST + 8),
                MIXERLINE_COMPONENTTYPE_SRC_FIRST = 0x1000,
                MIXERLINE_COMPONENTTYPE_SRC_LAST = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 10),

                // Audio line is a digital destination (for example, digital input to a DAT or CD audio device).
                MIXERLINE_COMPONENTTYPE_DST_DIGITAL = (MIXERLINE_COMPONENTTYPE_DST_FIRST + 1),
                // Audio line is an adjustable (gain and/or attenuation) destination intended to drive headphones.
                // Most audio cards use the same audio destination line for speakers and headphones, in which case the mixer device simply uses the MIXERLINE_COMPONENTTYPE_DST_SPEAKERS type.
                MIXERLINE_COMPONENTTYPE_DST_HEADPHONES = (MIXERLINE_COMPONENTTYPE_DST_FIRST + 5),
                // Audio line is a line level destination (for example, line level input from a CD audio device) that will be the final recording source for the analog-to-digital converter (ADC).
                // Because most audio cards for personal computers provide some sort of gain for the recording audio source line, the mixer device will use the MIXERLINE_COMPONENTTYPE_DST_WAVEIN type.
                MIXERLINE_COMPONENTTYPE_DST_LINE = (MIXERLINE_COMPONENTTYPE_DST_FIRST + 2),
                // Audio line is a destination used for a monitor.
                MIXERLINE_COMPONENTTYPE_DST_MONITOR = (MIXERLINE_COMPONENTTYPE_DST_FIRST + 3),
                // Audio line is an adjustable (gain and/or attenuation) destination intended to drive speakers. This is the typical component type for the audio output of audio cards for personal computers.
                MIXERLINE_COMPONENTTYPE_DST_SPEAKERS = (MIXERLINE_COMPONENTTYPE_DST_FIRST + 4),
                // Audio line is a destination that will be routed to a telephone line.
                MIXERLINE_COMPONENTTYPE_DST_TELEPHONE = (MIXERLINE_COMPONENTTYPE_DST_FIRST + 6),
                // Audio line is a destination that cannot be defined by one of the standard component types.
                // A mixer device is required to use this component type for line component types that have not been defined by Microsoft Corporation.
                MIXERLINE_COMPONENTTYPE_DST_UNDEFINED = (MIXERLINE_COMPONENTTYPE_DST_FIRST + 0),
                // Audio line is a destination that will be the final recording source for voice input.
                // This component type is exactly like MIXERLINE_COMPONENTTYPE_DST_WAVEIN but is intended specifically for settings used during voice recording/recognition.
                // Support for this line is optional for a mixer device. Many mixer devices provide only MIXERLINE_COMPONENTTYPE_DST_WAVEIN.
                MIXERLINE_COMPONENTTYPE_DST_VOICEIN = (MIXERLINE_COMPONENTTYPE_DST_FIRST + 8),
                // Audio line is a destination that will be the final recording source for the waveform-audio input (ADC).
                // This line typically provides some sort of gain or attenuation. This is the typical component type for the recording line of most audio cards for personal computers.
                MIXERLINE_COMPONENTTYPE_DST_WAVEIN = (MIXERLINE_COMPONENTTYPE_DST_FIRST + 7),
                // Audio line is an analog source (for example, analog output from a video-cassette tape).
                MIXERLINE_COMPONENTTYPE_SRC_ANALOG = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 10),
                // Audio line is a source originating from the auxiliary audio line.
                // This line type is intended as a source with gain or attenuation that can be routed to the MIXERLINE_COMPONENTTYPE_DST_SPEAKERS destination and/or recorded
                // from the MIXERLINE_COMPONENTTYPE_DST_WAVEIN destination.
                MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 9),
                // Audio line is a source originating from the output of an internal audio CD.
                // This component type is provided for audio cards that provide an audio source line intended to be connected to an audio CD (or CD-ROM playing an audio CD).
                MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 5),
                // Audio line is a digital source (for example, digital output from a DAT or audio CD).
                MIXERLINE_COMPONENTTYPE_SRC_DIGITAL = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 1),
                // Audio line is a line-level source (for example, line-level input from an external stereo) that can be used as an optional recording source.
                // Because most audio cards for personal computers provide some sort of gain for the recording source line, the mixer device will use the MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY type.
                MIXERLINE_COMPONENTTYPE_SRC_LINE = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 2),
                // Audio line is a microphone recording source. Most audio cards for personal computers provide at least two types of recording sources: an auxiliary audio line and microphone input.
                // A microphone audio line typically provides some sort of gain.
                // Audio cards that use a single input for use with a microphone or auxiliary audio line should use the MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE component type.
                MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 3),
                // Audio line is a source originating from personal computer speaker.
                // Several audio cards for personal computers provide the ability to mix what would typically be played on the internal speaker with the output of an audio card.
                // Some audio cards support the ability to use this output as a recording source.
                MIXERLINE_COMPONENTTYPE_SRC_PCSPEAKER = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 7),
                // Audio line is a source originating from the output of an internal synthesizer. Most audio cards for personal computers provide some sort of MIDI synthesizer.
                MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 4),
                // Audio line is a source originating from an incoming telephone line.
                MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 6),
                // Audio line is a source that cannot be defined by one of the standard component types.
                // A mixer device is required to use this component type for line component types that have not been defined by Microsoft Corporation.
                MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 0),
                // Audio line is a source originating from the waveform-audio output digital-to-analog converter (DAC).
                // Most audio cards for personal computers provide this component type as a source to the MIXERLINE_COMPONENTTYPE_DST_SPEAKERS destination.
                // Some cards also allow this source to be routed to the MIXERLINE_COMPONENTTYPE_DST_WAVEIN destination.
                MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 8)

            }

            /// <summary>
            /// mixercontrol -> dwControlType
            /// Class of the control for which the identifier is specified in dwControlID.
            /// </summary>
            [Flags]
            public enum CONTROLTYPE : uint
            {
                MIXERCONTROL_CT_CLASS_CUSTOM = 0x0,
                MIXERCONTROL_CT_CLASS_FADER = 0x50000000,
                MIXERCONTROL_CT_CLASS_LIST = 0x70000000,
                MIXERCONTROL_CT_CLASS_MASK = 0xF0000000,
                MIXERCONTROL_CT_CLASS_METER = 0x10000000,
                MIXERCONTROL_CT_CLASS_NUMBER = 0x30000000,
                MIXERCONTROL_CT_CLASS_SLIDER = 0x40000000,
                MIXERCONTROL_CT_CLASS_SWITCH = 0x20000000,
                MIXERCONTROL_CT_CLASS_TIME = 0x60000000,

                MIXERCONTROL_CT_SC_LIST_MULTIPLE = 0x1000000,
                MIXERCONTROL_CT_SC_LIST_SINGLE = 0x0,
                MIXERCONTROL_CT_SC_METER_POLLED = 0x0,
                MIXERCONTROL_CT_SC_SWITCH_BOOLEAN = 0x0,
                MIXERCONTROL_CT_SC_SWITCH_BUTTON = 0x1000000,
                MIXERCONTROL_CT_SC_TIME_MICROSECS = 0x0,
                MIXERCONTROL_CT_SC_TIME_MILLISECS = 0x1000000,
                MIXERCONTROL_CT_SUBCLASS_MASK = 0xF000000,
                MIXERCONTROL_CT_UNITS_BOOLEAN = 0x10000,
                MIXERCONTROL_CT_UNITS_CUSTOM = 0x0,
                MIXERCONTROL_CT_UNITS_DECIBELS = 0x40000,
                MIXERCONTROL_CT_UNITS_MASK = 0xFF0000,
                MIXERCONTROL_CT_UNITS_PERCENT = 0x50000,
                MIXERCONTROL_CT_UNITS_SIGNED = 0x20000,
                MIXERCONTROL_CT_UNITS_UNSIGNED = 0x30000,

                MIXERCONTROL_CONTROLTYPE_BASS = (MIXERCONTROL_CONTROLTYPE_FADER + 2),
                MIXERCONTROL_CONTROLTYPE_BOOLEAN = (MIXERCONTROL_CT_CLASS_SWITCH | MIXERCONTROL_CT_SC_SWITCH_BOOLEAN | MIXERCONTROL_CT_UNITS_BOOLEAN),
                MIXERCONTROL_CONTROLTYPE_BOOLEANMETER = (MIXERCONTROL_CT_CLASS_METER | MIXERCONTROL_CT_SC_METER_POLLED | MIXERCONTROL_CT_UNITS_BOOLEAN),
                MIXERCONTROL_CONTROLTYPE_BUTTON = (MIXERCONTROL_CT_CLASS_SWITCH | MIXERCONTROL_CT_SC_SWITCH_BUTTON | MIXERCONTROL_CT_UNITS_BOOLEAN),
                MIXERCONTROL_CONTROLTYPE_CUSTOM = (MIXERCONTROL_CT_CLASS_CUSTOM | MIXERCONTROL_CT_UNITS_CUSTOM),
                MIXERCONTROL_CONTROLTYPE_DECIBELS = (MIXERCONTROL_CT_CLASS_NUMBER | MIXERCONTROL_CT_UNITS_DECIBELS),
                MIXERCONTROL_CONTROLTYPE_EQUALIZER = (MIXERCONTROL_CONTROLTYPE_FADER + 4),
                MIXERCONTROL_CONTROLTYPE_FADER = (MIXERCONTROL_CT_CLASS_FADER | MIXERCONTROL_CT_UNITS_UNSIGNED),
                MIXERCONTROL_CONTROLTYPE_LOUDNESS = (MIXERCONTROL_CONTROLTYPE_BOOLEAN + 4),
                MIXERCONTROL_CONTROLTYPE_MICROTIME = (MIXERCONTROL_CT_CLASS_TIME | MIXERCONTROL_CT_SC_TIME_MICROSECS | MIXERCONTROL_CT_UNITS_UNSIGNED),
                MIXERCONTROL_CONTROLTYPE_MILLITIME = (MIXERCONTROL_CT_CLASS_TIME | MIXERCONTROL_CT_SC_TIME_MILLISECS | MIXERCONTROL_CT_UNITS_UNSIGNED),
                MIXERCONTROL_CONTROLTYPE_MIXER = (MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT + 1),
                MIXERCONTROL_CONTROLTYPE_MONO = (MIXERCONTROL_CONTROLTYPE_BOOLEAN + 3),
                MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT = (MIXERCONTROL_CT_CLASS_LIST | MIXERCONTROL_CT_SC_LIST_MULTIPLE | MIXERCONTROL_CT_UNITS_BOOLEAN),
                MIXERCONTROL_CONTROLTYPE_MUTE = (MIXERCONTROL_CONTROLTYPE_BOOLEAN + 2),
                MIXERCONTROL_CONTROLTYPE_MUX = (MIXERCONTROL_CONTROLTYPE_SINGLESELECT + 1),
                MIXERCONTROL_CONTROLTYPE_ONOFF = (MIXERCONTROL_CONTROLTYPE_BOOLEAN + 1),
                MIXERCONTROL_CONTROLTYPE_PAN = (MIXERCONTROL_CONTROLTYPE_SLIDER + 1),
                MIXERCONTROL_CONTROLTYPE_PEAKMETER = (MIXERCONTROL_CONTROLTYPE_SIGNEDMETER + 1),
                MIXERCONTROL_CONTROLTYPE_PERCENT = (MIXERCONTROL_CT_CLASS_NUMBER | MIXERCONTROL_CT_UNITS_PERCENT),
                MIXERCONTROL_CONTROLTYPE_QSOUNDPAN = (MIXERCONTROL_CONTROLTYPE_SLIDER + 2),
                MIXERCONTROL_CONTROLTYPE_SIGNED = (MIXERCONTROL_CT_CLASS_NUMBER | MIXERCONTROL_CT_UNITS_SIGNED),
                MIXERCONTROL_CONTROLTYPE_SIGNEDMETER = (MIXERCONTROL_CT_CLASS_METER | MIXERCONTROL_CT_SC_METER_POLLED | MIXERCONTROL_CT_UNITS_SIGNED),
                MIXERCONTROL_CONTROLTYPE_SINGLESELECT = (MIXERCONTROL_CT_CLASS_LIST | MIXERCONTROL_CT_SC_LIST_SINGLE | MIXERCONTROL_CT_UNITS_BOOLEAN),
                MIXERCONTROL_CONTROLTYPE_SLIDER = (MIXERCONTROL_CT_CLASS_SLIDER | MIXERCONTROL_CT_UNITS_SIGNED),
                MIXERCONTROL_CONTROLTYPE_STEREOENH = (MIXERCONTROL_CONTROLTYPE_BOOLEAN + 5),
                MIXERCONTROL_CONTROLTYPE_TREBLE = (MIXERCONTROL_CONTROLTYPE_FADER + 3),
                MIXERCONTROL_CONTROLTYPE_UNSIGNED = (MIXERCONTROL_CT_CLASS_NUMBER | MIXERCONTROL_CT_UNITS_UNSIGNED),
                MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER = (MIXERCONTROL_CT_CLASS_METER | MIXERCONTROL_CT_SC_METER_POLLED | MIXERCONTROL_CT_UNITS_UNSIGNED),
                MIXERCONTROL_CONTROLTYPE_VOLUME = (MIXERCONTROL_CONTROLTYPE_FADER + 1),
            }

            /// <summary>
            /// mixercontrol -> fdwControl
            /// Status and support flags for the audio line control.
            /// </summary>
            public enum CONTROLF : uint
            {
                /// <summary>
                /// This control is disabled.
                /// </summary>
                MIXERCONTROL_CONTROLF_DISABLED = 0x80000000,

                /// <summary>
                /// This control has multiple channels, but only one value for
                /// all of them.
                /// </summary>
                MIXERCONTROL_CONTROLF_UNIFORM = 0x1,

                /// <summary>
                /// This control has multiple values for one channel (like an equalizer).
                /// </summary>
                MIXERCONTROL_CONTROLF_MULTIPLE = 0x2
            }
        }
        public class Query
        {
            // Complete list of all types of 'hmxobj parameter'
            // look at :: mixerOpenFlags, LineInfoFlags, LineControlsFlags

            //
            // MixerOpen Handle [of specific flag]
            //

            [DllImport("winmm", SetLastError = true)]
            public static extern int mixerGetNumDevs();

            [DllImport("winmm.dll", SetLastError = true)]
            public static extern int auxGetNumDevs();

            [DllImport("winmm.dll", SetLastError = true)]
            public static extern int midiInGetNumDevs();

            [DllImport("winmm.dll", SetLastError = true)]
            public static extern int midiOutGetNumDevs();

            [DllImport("winmm.dll", SetLastError = true)]
            public static extern int waveInGetNumDevs();

            [DllImport("winmm.dll", SetLastError = true)]
            public static extern int waveOutGetNumDevs();

            //
            // wave Handle
            // http://winmm.codeplex.com
            //

            // waveOutOpen
            // waveInOpen
            // waveOutClose
            // waveInClose

            //
            // midi Handle
            // http://winmm.codeplex.com
            //

            // midiOutOpen
            // midiInOpen
            // midiOutClose
            // midiInClose
        }
    }

    /// <summary>
    /// Core Audio APIs
    /// http://msdn.microsoft.com/en-us/library/windows/desktop/dd370802(v=vs.85).aspx
    /// 
    /// Programming Reference
    /// http://msdn.microsoft.com/en-us/library/windows/desktop/dd316602(v=vs.85).aspx
    /// </summary>
    public class Vista
    {
        //
        // IMMDeviceEnumerator -> enable to to enumarate all device in system [.EnumAudioEndpoints( out ...]
        //

        // The DEVICE_STATE_XXX constants indicate the current state of an audio endpoint device.
        [Flags]
        public enum EDeviceState : uint
        {
            DEVICE_STATE_ACTIVE = 0x00000001,
            DEVICE_STATE_UNPLUGGED = 0x00000002,
            DEVICE_STATE_NOTPRESENT = 0x00000004,
            DEVICE_STATEMASK_ALL = 0x00000007
        }

        // The EDataFlow enumeration defines constants that indicate the direction in which audio data flows between an audio endpoint device and an application.
        public enum EDataFlow
        {
            eRender = 0,
            eCapture = 1,
            eAll = 2,
            EDataFlow_enum_count = 3
        }

        // The ERole enumeration defines constants that indicate the role that the system has assigned to an audio endpoint device.
        public enum ERole
        {
            eConsole = 0,
            eMultimedia = 1,
            eCommunications = 2,
            ERole_enum_count = 3
        }

        // The IMMDeviceEnumerator interface provides methods for enumerating multimedia device resources.
        [Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IMMDeviceEnumerator
        {
            // Generates a collection of audio endpoint devices that meet the specified criteria.
            [PreserveSig]
            int EnumAudioEndpoints(EDataFlow dataFlow, EDeviceState StateMask, out IMMDeviceCollection device);
            
            // Retrieves the default audio endpoint for the specified data-flow direction and role.
            [PreserveSig]
            int GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role, out IMMDevice ppEndpoint);

            // Retrieves an endpoint device that is specified by an endpoint device-identification string.
            [PreserveSig]
            int GetDevice(string pwstrId, out IMMDevice ppDevice);

            // Registers a client's notification callback interface.
            [PreserveSig]
            int RegisterEndpointNotificationCallback(IMMNotificationClient pClient);

            // Deletes the registration of a notification interface that the client registered in a previous call to the IMMDeviceEnumerator::RegisterEndpointNotificationCallback method.
            [PreserveSig]
            int UnregisterEndpointNotificationCallback(IMMNotificationClient pClient);
        }

        //
        // IMMDeviceCollection -> contain collection of all devices in system
        //

        // Activate [types] {default use :: CLSCTX_ALL}
        // Values that are used in activation calls to indicate the execution contexts in which an object is to be run. 
        [Flags]
        public enum CLSCTX : uint
        {
            /// <summary>
            /// The code that creates and manages objects of this class is a DLL that runs in the same process as the caller of the function specifying the class context.
            /// </summary>
            CLSCTX_INPROC_SERVER = 0x1,

            /// <summary>
            /// The code that manages objects of this class is an in-process handler.
            /// This is a DLL that runs in the client process and implements client-side structures of this class when instances of the class are accessed remotely.
            /// </summary>
            CLSCTX_INPROC_HANDLER = 0x2,

            /// <summary>
            /// The EXE code that creates and manages objects of this class runs on same machine but is loaded in a separate process space.
            /// </summary>
            CLSCTX_LOCAL_SERVER = 0x4,

            /// <summary>
            /// A remote context. The LocalServer32 or LocalService code that creates and manages objects of this class is run on a different computer.
            /// </summary>
            CLSCTX_REMOTE_SERVER = 0x10,

            /// <summary>
            /// Disaables the downloading of code from the directory service or the Internet.
            /// This flag cannot be set at the same time as CLSCTX_ENABLE_CODE_DOWNLOAD.
            /// </summary>
            CLSCTX_NO_CODE_DOWNLOAD = 0x400,

            /// <summary>
            /// Enables the downloading of code from the directory service or the Internet.
            /// This flag cannot be set at the same time as CLSCTX_NO_CODE_DOWNLOAD.
            /// </summary>
            CLSCTX_ENABLE_CODE_DOWNLOAD = 0x2000,

            /// <summary>
            /// Specify if you want the activation to fail if it uses custom marshalling.
            /// </summary>
            CLSCTX_NO_CUSTOM_MARSHAL = 0x1000,

            /// <summary>
            /// Disables activate-as-activator (AAA) activations for this activation only. 
            /// </summary>
            CLSCTX_DISABLE_AAA = 0x8000,

            /// <summary>
            /// Enables activate-as-activator (AAA) activations for this activation only. 
            /// </summary>
            CLSCTX_ENABLE_AAA = 0x10000,

            /// <summary>
            /// Begin this activation from the default context of the current apartment.
            /// </summary>
            CLSCTX_FROM_DEFAULT_CONTEXT = 0x20000,

            /// <summary>
            /// Activate or connect to a 32-bit version of the server; fail if one is not registered.
            /// </summary>
            CLSCTX_ACTIVATE_32_BIT_SERVER = 0x40000,

            /// <summary>
            /// Activate or connect to a 64 bit version of the server; fail if one is not registered.
            /// </summary>
            CLSCTX_ACTIVATE_64_BIT_SERVER = 0x80000,
            
            /// <summary>
            /// When this flag is specified, COM uses the impersonation token of the thread, if one is present,
            /// for the activation request made by the thread.
            /// When this flag is not specified or if the thread does not have an impersonation token,
            /// COM uses the process token of the thread's process for the activation request made by the thread.
            /// </summary>
            CLSCTX_ENABLE_CLOAKING = 0x100000,

            /// <summary>
            /// TBD
            /// </summary>
            CLSCTX_PS_DLL = 0x80000000,
            
            /// <summary>
            /// all Server option
            /// </summary>
            CLSCTX_SERVER = (CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER),

            /// <summary>
            /// All option
            /// </summary>
            CLSCTX_ALL = (CLSCTX_INPROC_HANDLER | CLSCTX_SERVER)
        }

        // The storage-access mode.
        public enum EStgmAccess
        {
            STGM_READ = 0x00000000,
            STGM_WRITE = 0x00000001,
            STGM_READWRITE = 0x00000002
        }
        // Specifies the FMTID/PID identifier that programmatically identifies a property. Replaces SHCOLUMNID.
        public struct PropertyKey
        {
            public Guid fmtid;
            public int pid;
        };
        [StructLayout(LayoutKind.Explicit)]
        // Properties of PropertyKey
        public struct PropVariant
        {
            [FieldOffset(0)]
            short vt;
            [FieldOffset(2)]
            short wReserved1;
            [FieldOffset(4)]
            short wReserved2;
            [FieldOffset(6)]
            short wReserved3;
            [FieldOffset(8)]
            sbyte cVal;
            [FieldOffset(8)]
            byte bVal;
            [FieldOffset(8)]
            short iVal;
            [FieldOffset(8)]
            ushort uiVal;
            [FieldOffset(8)]
            int lVal;
            [FieldOffset(8)]
            uint ulVal;
            [FieldOffset(8)]
            long hVal;
            [FieldOffset(8)]
            ulong uhVal;
            [FieldOffset(8)]
            float fltVal;
            [FieldOffset(8)]
            double dblVal;
            [FieldOffset(8)]
            Blob blobVal;
            [FieldOffset(8)]
            DateTime date;
            [FieldOffset(8)]
            bool boolVal;
            [FieldOffset(8)]
            int scode;
            [FieldOffset(8)]
            System.Runtime.InteropServices.ComTypes.FILETIME filetime;
            [FieldOffset(8)]
            IntPtr everything_else;

            //I'm sure there is a more efficient way to do this but this works ..for now..
            internal byte[] GetBlob()
            {
                byte[] Result = new byte[blobVal.Length];
                for (int i = 0; i < blobVal.Length; i++)
                {
                    Result[i] = Marshal.ReadByte((IntPtr)((long)(blobVal.Data) + i));
                }
                return Result;
            }

            public object Value
            {
                get
                {
                    VarEnum ve = (VarEnum)vt;
                    switch (ve)
                    {
                        case VarEnum.VT_I1:
                            return bVal;
                        case VarEnum.VT_I2:
                            return iVal;
                        case VarEnum.VT_I4:
                            return lVal;
                        case VarEnum.VT_I8:
                            return hVal;
                        case VarEnum.VT_INT:
                            return iVal;
                        case VarEnum.VT_UI4:
                            return ulVal;
                        case VarEnum.VT_LPWSTR:
                            return Marshal.PtrToStringUni(everything_else);
                        case VarEnum.VT_BLOB:
                            return GetBlob();
                    }
                    return "FIXME Type = " + ve.ToString();
                }
            }

        }
        // Member of PropVariant
        public struct Blob
        {
            public int Length;
            public IntPtr Data;
        }

        // The IMMDeviceCollection interface represents a collection of multimedia device resources.
        // In the current implementation, the only device resources that the MMDevice API can create collections of are audio endpoint devices.
        [Guid("0BD7A1BE-7A1A-44DB-8397-CC5392387B5E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IMMDeviceCollection
        {
            // Retrieves a count of the devices in the device collection.
            [PreserveSig]
            int GetCount(out uint pcDevices);

            // Retrieves a pointer to the specified item in the device collection.
            [PreserveSig]
            int Item(uint nDevice, out IMMDevice Device);
        }

        // The IMMDevice interface encapsulates the generic features of a multimedia device resource.
        [Guid("D666063F-1587-4E43-81F1-B948E807363F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IMMDevice
        {
            // Creates a COM object with the specified interface.
            [PreserveSig]
            int Activate(ref Guid iid, CLSCTX dwClsCtx, IntPtr pActivationParams, [MarshalAs(UnmanagedType.IUnknown)] out object ppInterface);
            
            // get device property store.
            [PreserveSig]
            int OpenPropertyStore(EStgmAccess stgmAccess, out IPropertyStore propertyStore);

            // Gets a string that identifies the device.
            [PreserveSig]
            int GetId([MarshalAs(UnmanagedType.LPWStr)] out string ppstrId);

            // Gets the current state of the device.
            [PreserveSig]
            int GetState(out EDeviceState pdwState);
        }

        // Exposes methods for enumerating, getting, and setting property values.
        [Guid("886d8eeb-8cf2-4446-8d02-cdba1dbdcf99"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IPropertyStore
        {
            // Gets the number of properties attached to the file.
            [PreserveSig]
            int GetCount(out Int32 count);

            // Gets a property key from an item's array of properties.
            [PreserveSig]
            int GetAt(int iProp, out PropertyKey pkey);

            // Sets a new property value, or replaces or removes an existing value.
            [PreserveSig]
            int GetValue(ref PropertyKey key, out PropVariant pv);

            // Gets data for a specific property.
            [PreserveSig]
            int SetValue(ref PropertyKey key, ref PropVariant propvar);

            // Saves a property change.
            [PreserveSig]
            int Commit();
        }

        //
        // IMMDevice >> IAudioEndpointVolume
        //

        // IAudioEndpointVolume > get Volume / Mute [State] of device
        [Guid("5CDF2C82-841E-4546-9722-0CF74078229A"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IAudioEndpointVolume
        {
            // Registers a client's notification callback interface.
            [PreserveSig]
            int RegisterControlChangeNotify(IAudioEndpointVolumeCallback pNotify);

            // Deletes the registration of a client's notification callback interface.
            [PreserveSig]
            int UnregisterControlChangeNotify(IAudioEndpointVolumeCallback pNotify);

            // Gets a count of the channels in the audio stream.
            [PreserveSig]
            int GetChannelCount(out int pnChannelCount);

            // Sets the master volume level of the audio stream, in decibels.
            [PreserveSig]
            int SetMasterVolumeLevel(float fLevelDB, Guid pguidEventContext);

            // Sets the master volume level, expressed as a normalized, audio-tapered value.
            [PreserveSig]
            int SetMasterVolumeLevelScalar(float fLevel, Guid pguidEventContext);

            // Gets the master volume level of the audio stream, in decibels.
            [PreserveSig]
            int GetMasterVolumeLevel(out float pfLevelDB);

            // Gets the master volume level, expressed as a normalized, audio-tapered value.
            [PreserveSig]
            int GetMasterVolumeLevelScalar(out float pfLevel);

            // Sets the volume level, in decibels, of the specified channel of the audio stream.
            [PreserveSig]
            int SetChannelVolumeLevel(uint nChannel, float fLevelDB, Guid pguidEventContext);

            // Sets the normalized, audio-tapered volume level of the specified channel in the audio stream.
            [PreserveSig]
            int SetChannelVolumeLevelScalar(uint nChannel, float fLevel, Guid pguidEventContext);

            // Gets the volume level, in decibels, of the specified channel in the audio stream.
            [PreserveSig]
            int GetChannelVolumeLevel(uint nChannel, out float pfLevelDB);

            // Gets the normalized, audio-tapered volume level of the specified channel of the audio stream.
            [PreserveSig]
            int GetChannelVolumeLevelScalar(uint nChannel, out float pfLevel);

            // Sets the muting state of the audio stream.
            [PreserveSig]
            int SetMute([MarshalAs(UnmanagedType.Bool)] Boolean bMute, Guid pguidEventContext);

            // Gets the muting state of the audio stream.
            [PreserveSig]
            int GetMute(out bool pbMute);

            // Gets information about the current step in the volume range.
            [PreserveSig]
            int GetVolumeStepInfo(out uint pnStep, out uint pnStepCount);

            // Increases the volume level by one step.
            [PreserveSig]
            int VolumeStepUp(Guid pguidEventContext);

            // Decreases the volume level by one step.
            [PreserveSig]
            int VolumeStepDown(Guid pguidEventContext);

            // Queries the audio endpoint device for its hardware-supported functions.
            [PreserveSig]
            int QueryHardwareSupport(out uint pdwHardwareSupportMask);

            // Gets the volume range of the audio stream, in decibels.
            [PreserveSig]
            int GetVolumeRange(out float pflVolumeMindB, out float pflVolumeMaxdB, out float pflVolumeIncrementdB);
        }

        //
        // IMMDevice >> IAudioSessionManager
        //

        // The AudioSessionState enumeration defines constants that indicate the current state of an audio session.
        public enum AudioSessionState
        {
            // inActive
            AudioSessionStateInactive = 0,
            // Active
            AudioSessionStateActive = 1,
            // Expired
            AudioSessionStateExpired = 2
        }

        // The reason that the audio session was disconnected.
        public enum AudioSessionDisconnectReason
        {
            // Device Removal
            DisconnectReasonDeviceRemoval = 0,

            // Server Shutdown
            DisconnectReasonServerShutdown = (DisconnectReasonDeviceRemoval + 1),

            // Format Changed
            DisconnectReasonFormatChanged = (DisconnectReasonServerShutdown + 1),

            // Session Logoff
            DisconnectReasonSessionLogoff = (DisconnectReasonFormatChanged + 1),

            // Session Disconnected
            DisconnectReasonSessionDisconnected = (DisconnectReasonSessionLogoff + 1),

            // Exclusive Mode Override
            DisconnectReasonExclusiveModeOverride = (DisconnectReasonSessionDisconnected + 1)
        }
        
        /* The IAudioSessionManager2 interface inherits from IAudioSessionManager. */
        // IAudioSessionManager > get all Session [Program use that device] ofdevice
        [Guid("77AA99A0-1BD6-484F-8BC7-2C654C9A9B6F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IAudioSessionManager2
        {
            /*** IAudioSessionManager methods ***/

            // Retrieves an audio session control.
            [PreserveSig]
            int GetAudioSessionControl(ref Guid AudioSessionGuid, UInt32 StreamFlags, ref IAudioSessionControl ISessionControl);

            // Retrieves a simple audio volume control.
            [PreserveSig]
            int GetSimpleAudioVolume(ref Guid AudioSessionGuid, UInt32 StreamFlags, ref ISimpleAudioVolume ISimpleAudioVolume);

            /*** IAudioSessionManager2 methods ***/

            // Gets a pointer to the audio session enumerator object used to enumerate sessions.
            [PreserveSig]
            int GetSessionEnumerator(out IAudioSessionEnumerator SessionEnum);

            // Registers the application to receive a notification when a session is created.
            [PreserveSig]
            int RegisterSessionNotification(IAudioSessionNotification IAudioSessionNotification);

            // Deletes the registration to receive a notification when a session is created.
            [PreserveSig]
            int UnregisterSessionNotification(IAudioSessionNotification IAudioSessionNotification);

            // Registers the application to receive ducking notifications.
            [PreserveSig]
            int RegisterDuckNotification(string sessionID, IntPtr IAudioVolumeDuckNotification);

            // Deletes the registration to receive ducking notifications.
            [PreserveSig]
            int UnregisterDuckNotification(IntPtr IAudioVolumeDuckNotification);
        }

        // enumerates audio sessions on an audio device. 
        [Guid("E2F5BB11-0570-40CA-ACDD-3AA01277DEE8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IAudioSessionEnumerator
        {
            // Gets the total number of audio sessions that are open on the audio device.
            [PreserveSig]
            int GetCount(out int SessionCount);

            // Gets the audio session specified by an audio session number.
            [PreserveSig]
            int GetSession(int SessionCount, out IAudioSessionControl Session);
        }

        // The IAudioSessionControl interface enables a client to configure the control parameters for an audio session and to monitor events in the session
        [Guid("F4B1A599-7266-4319-A8CA-E70ACB11E8CD"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IAudioSessionControl
        {
            // Retrieves the current state of the audio session.
            [PreserveSig]
            int GetState(out AudioSessionState state);

            // Retrieves the display name for the audio session.
            [PreserveSig]
            int GetDisplayName(out IntPtr name);

            // Assigns a display name to the current audio session.
            [PreserveSig]
            int SetDisplayName(string value, Guid EventContext);

            // Retrieves the path for the display icon for the audio session.
            [PreserveSig]
            int GetIconPath(out IntPtr Path);

            // Assigns a display icon to the current session.
            [PreserveSig]
            int SetIconPath(string Value, Guid EventContext);

            // Retrieves the grouping parameter of the audio session.
            [PreserveSig]
            int GetGroupingParam(out Guid GroupingParam);

            // Assigns a session to a grouping of sessions.
            [PreserveSig]
            int SetGroupingParam(Guid Override, Guid Eventcontext);

            // Registers the client to receive notifications of session events, including changes in the session state.
            [PreserveSig]
            int RegisterAudioSessionNotification(IAudioSessionEvents NewNotifications);

            // Deletes a previous registration by the client to receive notifications.
            [PreserveSig]
            int UnregisterAudioSessionNotification(IAudioSessionEvents NewNotifications);
        }

        // The IAudioSessionControl2 interface can be used by a client to get information about the audio session.
        [Guid("bfb7ff88-7239-4fc9-8fa2-07c950be9c6d"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IAudioSessionControl2
        {
            /*** IAudioSessionControl methods ***/

            // Retrieves the current state of the audio session.
            [PreserveSig]
            int GetState(out AudioSessionState state);

            // Retrieves the display name for the audio session.
            [PreserveSig]
            int GetDisplayName(out IntPtr name);

            // Assigns a display name to the current audio session.
            [PreserveSig]
            int SetDisplayName(string value, Guid EventContext);

            // Retrieves the path for the display icon for the audio session.
            [PreserveSig]
            int GetIconPath(out IntPtr Path);

            // Assigns a display icon to the current session.
            [PreserveSig]
            int SetIconPath(string Value, Guid EventContext);

            // Retrieves the grouping parameter of the audio session.
            [PreserveSig]
            int GetGroupingParam(out Guid GroupingParam);

            // Assigns a session to a grouping of sessions.
            [PreserveSig]
            int SetGroupingParam(Guid Override, Guid Eventcontext);

            // Registers the client to receive notifications of session events, including changes in the session state.
            [PreserveSig]
            int RegisterAudioSessionNotification(IAudioSessionEvents NewNotifications);

            // Deletes a previous registration by the client to receive notifications.
            [PreserveSig]
            int UnregisterAudioSessionNotification(IAudioSessionEvents NewNotifications);
            
            /*** IAudioSessionControl2 methods ***/

            // Retrieves the session identifier.
            [PreserveSig]
            int GetSessionIdentifier([Out] [MarshalAs(UnmanagedType.LPWStr)] out string sessionId);

            // Retrieves the identifier of the session instance.
            [PreserveSig]
            int GetSessionInstanceIdentifier([Out] [MarshalAs(UnmanagedType.LPWStr)] out string instanceId);

            // Retrieves the process identifier of the session.
            [PreserveSig]
            int GetProcessId(out UInt32 retvVal);

            // Indicates whether the session is a system sounds session.
            [PreserveSig]
            int IsSystemSoundsSession();

            // Enables or disables the default stream attenuation experience (auto-ducking) provided by the system.
            [PreserveSig]
            int SetDuckingPreference(bool optOut);
        }

        // The ISimpleAudioVolume interface enables a client to control the master volume level of an audio session.
        [Guid("87CE5498-68D6-44E5-9215-6DA47EF883D8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface ISimpleAudioVolume
        {
            // Sets the master volume level for the audio session.
            [PreserveSig]
            int SetMasterVolume(float fLevel, ref Guid EventContext);

            // Retrieves the client volume level for the audio session.
            [PreserveSig]
            int GetMasterVolume(out float pfLevel);

            // Sets the muting state for the audio session.
            [PreserveSig]
            int SetMute(bool bMute, ref Guid EventContext);

            // Retrieves the current muting state for the audio session.
            [PreserveSig]
            int GetMute(out bool bMute);
        }

        //
        // Callback
        //

        // IMMDeviceEnumerator      -> device state change [ Add / Remove ]
        [Guid("7991EEC9-7E89-4D85-8390-6C703CEC60C0"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IMMNotificationClient
        {
            /// <summary>
            /// Notifies the client that the default audio endpoint device for a particular role has changed.
            /// </summary>
            /// <param name="deviceId">The endpoint ID string that identifies the audio endpoint device.</param>
            /// <param name="newState">The <see cref="DEVICE_STATE_XXX"/> constant that indicates the new state.</param>
            void OnDeviceStateChanged(
                [MarshalAs(UnmanagedType.LPWStr)] string deviceId,
                [MarshalAs(UnmanagedType.U4)] UInt32 newState);

            /// <summary>
            /// Indicates that a new audio endpoint device has been added.
            /// </summary>
            /// <param name="deviceId">The endpoint ID string that identifies the audio endpoint device.</param>
            void OnDeviceAdded(
                [MarshalAs(UnmanagedType.LPWStr)] string deviceId);

            /// <summary>
            /// Indicates that an audio endpoint device has been removed.
            /// </summary>
            /// <param name="deviceId">The endpoint ID string that identifies the audio endpoint device.</param>
            void OnDeviceRemoved(
                [MarshalAs(UnmanagedType.LPWStr)] string deviceId);

            /// <summary>
            /// Notifies the client that the default audio endpoint device for a particular role has changed.
            /// </summary>
            /// <param name="dataFlow">The data-flow direction of the endpoint device.</param>
            /// <param name="deviceRole">The device role of the audio endpoint device.</param>
            /// <param name="defaultDeviceId">The endpoint ID string that identifies the audio endpoint device.</param>
            void OnDefaultDeviceChanged(
                [MarshalAs(UnmanagedType.I4)] EDataFlow dataFlow,
                [MarshalAs(UnmanagedType.I4)] ERole deviceRole,
                [MarshalAs(UnmanagedType.LPWStr)] string defaultDeviceId);

            /// <summary>
            /// Indicates that the value of a property belonging to an audio endpoint device has changed.
            /// </summary>
            /// <param name="deviceId">The endpoint ID string that identifies the audio endpoint device.</param>
            /// <param name="propertyKey">A <see cref="PROPERTYKEY"/> that specifies the type of property.</param>
            void OnPropertyValueChanged(
                [MarshalAs(UnmanagedType.LPWStr)] string deviceId, PropertyKey propertyKey);
        }

        // IAudioEndpointVolume     -> device State change [ Vol / Mute ]
        [Guid("657804FA-D6AD-4496-8A60-352752AF4F89"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IAudioEndpointVolumeCallback
        {
            [PreserveSig]
            int OnNotify(IntPtr pNotifyData);
        };

        // IAudioSessionControl     -> session State change [ Vol / Mute
        [Guid("24918ACC-64B3-37C1-8CA9-74A66E9957A8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IAudioSessionEvents
        {
            [PreserveSig]
            int OnDisplayNameChanged([MarshalAs(UnmanagedType.LPWStr)] string NewDisplayName, Guid EventContext);
            [PreserveSig]
            int OnIconPathChanged([MarshalAs(UnmanagedType.LPWStr)] string NewIconPath, Guid EventContext);
            [PreserveSig]
            int OnSimpleVolumeChanged(float NewVolume, bool newMute, Guid EventContext);
            [PreserveSig]
            int OnChannelVolumeChanged(UInt32 ChannelCount, IntPtr NewChannelVolumeArray, UInt32 ChangedChannel, Guid EventContext);
            [PreserveSig]
            int OnGroupingParamChanged(Guid NewGroupingParam, Guid EventContext);
            [PreserveSig]
            int OnStateChanged(AudioSessionState NewState);
            [PreserveSig]
            int OnSessionDisconnected(AudioSessionDisconnectReason DisconnectReason);
        }

        // IAudioSessionManager     -> session State change
        [Guid("641DD20B-4D41-49CC-ABA3-174B9477BB08"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IAudioSessionNotification
        {
            [PreserveSig]
            int OnSessionCreated(IAudioSessionControl sessionControl);
        }
    }
}